home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / BORLAND TURBO / BATCH.PAK / BATCHDOC.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  23.0 KB  |  820 lines

  1. /**************************************************************************
  2.  *
  3.  *  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4.  *  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5.  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6.  *  PURPOSE.
  7.  *
  8.  *  Copyright (c) 1994 - 1995    Microsoft Corporation.    All Rights Reserved.
  9.  *
  10.  **************************************************************************/
  11. // batchdoc.cpp : implementation of the CBatchDoc class
  12. //
  13.  
  14. #define INC_OLE2
  15. #include "stdafx.h"
  16. #include "mainfrm.h"
  17. #include "batch.h"
  18. #include "batchdoc.h"
  19. #include "destdird.h"
  20. #include "interlea.h"
  21.  
  22. #ifdef _DEBUG
  23. #undef THIS_FILE
  24. static char BASED_CODE THIS_FILE[] = __FILE__;
  25. #endif
  26.  
  27. #if defined WIN32 && !defined UNICODE   // Chicago only
  28.  
  29. /*
  30.  * convert a UNICODE string to 'normal'
  31.  */
  32. LPTSTR WINAPI aviWideToText (LPTSTR lpszOut, LPWSTR lpwIn, UINT cch)
  33. {
  34.    if (sizeof(TCHAR) != sizeof(WCHAR))
  35.       WideCharToMultiByte(CP_ACP, 0, lpwIn, cch, lpszOut, cch, NULL, NULL);
  36.    else
  37.       lstrcpyn (lpszOut, (LPTSTR)lpwIn, cch);
  38.    return lpszOut;
  39. }
  40. #else
  41.  #define aviWideToText(lpszOut,lpwIn,cch) lstrcpyn(lpszOut,lpwIn,cch)
  42. #endif // WIN32 on CHICAGO
  43.  
  44. /////////////////////////////////////////////////////////////////////////////
  45. // CBatchDoc
  46.  
  47. IMPLEMENT_DYNCREATE(CBatchDoc, CDocument)
  48.  
  49. BEGIN_MESSAGE_MAP(CBatchDoc, CDocument)
  50.     //{{AFX_MSG_MAP(CBatchDoc)
  51.     ON_COMMAND(ID_OPTIONS_COMPRESS, OnOptionsCompress)
  52.     ON_COMMAND(ID_OPTIONS_VIDEO, OnOptionsVideo)
  53.     ON_COMMAND(ID_OPTIONS_AUDIO, OnOptionsAudio)
  54.     ON_COMMAND(ID_OPTIONS_TARGETDIRECTORY, OnOptionsTargetDir)
  55.     ON_COMMAND(ID_OPTIONS_ADDFILE, OnOptionsAddfile)
  56.     ON_COMMAND(ID_OPTIONS_INTERLEAVE, OnOptionsInterleave)
  57.     ON_UPDATE_COMMAND_UI(ID_OPTIONS_COMPRESS, OnUpdateCompress)
  58.     ON_UPDATE_COMMAND_UI(ID_OPTIONS_ADDFILE, OnUpdateAddfile)
  59.     ON_UPDATE_COMMAND_UI(ID_OPTIONS_AUDIO, OnUpdateAudio)
  60.     ON_UPDATE_COMMAND_UI(ID_OPTIONS_INTERLEAVE, OnUpdateInterleave)
  61.     ON_UPDATE_COMMAND_UI(ID_OPTIONS_TARGETDIRECTORY, OnUpdateTargetDir)
  62.     ON_UPDATE_COMMAND_UI(ID_OPTIONS_VIDEO, OnUpdateVideo)
  63.     ON_UPDATE_COMMAND_UI(ID_OPTIONS_DELETESELECTEDFILES, OnUpdateDeleteSel)
  64.     ON_COMMAND(ID_OPTIONS_DELETESELECTEDFILES, OnOptionsDeleteSel)
  65.     ON_UPDATE_COMMAND_UI(ID_FILE_CLOSE, OnUpdateFileClose)
  66.     ON_UPDATE_COMMAND_UI(ID_FILE_SAVE, OnUpdateFileSave)
  67.     ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_AS, OnUpdateFileSaveAs)
  68.     //}}AFX_MSG_MAP
  69. END_MESSAGE_MAP()
  70.  
  71. /////////////////////////////////////////////////////////////////////////////
  72. // CBatchDoc construction/destruction
  73.  
  74. CBatchDoc::CBatchDoc()
  75. {
  76.     // put one-time construction code here
  77.  
  78.     _fmemset(&AVIVideoOptions, 0, sizeof(AVIVideoOptions));
  79.     _fmemset(&AVIAudioOptions, 0, sizeof(AVIAudioOptions));
  80.     // Default to tightly interleaved
  81.     AVIAudioOptions.dwFlags |= AVICOMPRESSF_INTERLEAVE;
  82.     AVIAudioOptions.dwInterleaveEvery = 1;
  83.     fCompressing = fStopPlease = FALSE;
  84.     
  85. }
  86.  
  87. CBatchDoc::~CBatchDoc()
  88. {
  89.     LPAVICOMPRESSOPTIONS pOpt;
  90.  
  91.     // Free our Compression Options stuff
  92.     pOpt = &AVIVideoOptions;
  93.     AVISaveOptionsFree(1, &pOpt);
  94.     pOpt = &AVIAudioOptions;
  95.     AVISaveOptionsFree(1, &pOpt);
  96. }
  97.  
  98. BOOL CBatchDoc::OnNewDocument()
  99. {
  100.     if (!CDocument::OnNewDocument())
  101.         return FALSE;
  102.  
  103.     // TODO: add reinitialization code here
  104.     // (SDI documents will reuse this document)
  105.             
  106.     return TRUE;
  107. }
  108.  
  109. /////////////////////////////////////////////////////////////////////////////
  110. // CBatchDoc serialization
  111.  
  112. #define COOKIE TEXT("SATY")
  113.  
  114. //
  115. // The Load and Save code
  116. //
  117. // Each document can save its current settings as a .BCF file (Batch Compression
  118. // File).  This file looks like this:
  119. // - 4 CHAR ID
  120. // - COMPRESSIONOPTIONS struct for all video streams
  121. // - extra bytes for video compressor specific data if cbParms > 0
  122. // - COMPRESSIONOPTIONS struct for all audio streams
  123. // - extra bytes for audio compressor specific data if cbFormat > 0
  124. // - the name of the target directory as a CString
  125. // - the list of all files in the document as a CStringList
  126. //
  127. void CBatchDoc::Serialize(CArchive& ar)
  128. {
  129.     CString foo;
  130.     TCHAR szCookie[10];
  131.  
  132.     if (ar.IsStoring())
  133.     {
  134.         // Storing code
  135.  
  136.         ar.Write(COOKIE, lstrlen(COOKIE) + 1);
  137.         ar.Write(&AVIVideoOptions, sizeof(AVIVideoOptions));
  138.         if (AVIVideoOptions.cbParms > 0)
  139.             ar.Write(AVIVideoOptions.lpParms, AVIVideoOptions.cbParms);
  140.         ar.Write(&AVIAudioOptions, sizeof(AVIAudioOptions));
  141.         if (AVIAudioOptions.cbFormat > 0)
  142.             ar.Write(AVIAudioOptions.lpFormat, AVIAudioOptions.cbFormat);
  143.         ar << TargetDir;
  144.         FileList.Serialize(ar);
  145.         
  146.     // LOADING code.
  147.     } else {
  148.         LPAVICOMPRESSOPTIONS pOpt;
  149.  
  150.         // First verify it's a valid file
  151.         ar.Read(szCookie, lstrlen(COOKIE) + 1);
  152.         szCookie[lstrlen(COOKIE)] = TEXT('\0');
  153.         if (lstrcmp(szCookie, COOKIE)) {
  154.             MessageBox(AfxGetMainWnd()->m_hWnd,
  155.                 TEXT("Invalid Batch Compressor File"),
  156.                 TEXT("File Open Error"),
  157.                 MB_ICONEXCLAMATION | MB_OK);
  158.             return;
  159.            }
  160.  
  161.         // Next free whatever is there already
  162.         pOpt = &AVIVideoOptions;
  163.         AVISaveOptionsFree(1, &pOpt);
  164.         pOpt = &AVIAudioOptions;
  165.         AVISaveOptionsFree(1, &pOpt);
  166.  
  167.         ar.Read(&AVIVideoOptions, sizeof(AVIVideoOptions));
  168.         if (AVIVideoOptions.cbParms > 0) {
  169.             AVIVideoOptions.lpParms = GlobalAllocPtr(GPTR, AVIVideoOptions.cbParms);
  170.             ar.Read(AVIVideoOptions.lpParms, AVIVideoOptions.cbParms);
  171.         }
  172.            ar.Read(&AVIAudioOptions, sizeof(AVIAudioOptions));
  173.         if (AVIAudioOptions.cbFormat > 0) {
  174.             AVIAudioOptions.lpFormat = GlobalAllocPtr(GPTR, AVIAudioOptions.cbFormat);
  175.             ar.Read(AVIAudioOptions.lpFormat, AVIAudioOptions.cbFormat);
  176.         }
  177.         ar >> TargetDir;
  178.         FileList.Serialize(ar);
  179.         // FixListBox(); // hasn't been created yet.  It'll happen.
  180.     }    
  181. }
  182.  
  183. //
  184. // Something in the window changed - redraw it
  185. //
  186. void CBatchDoc::FixListBox()
  187. {
  188.     TCHAR szText[MAX_PATH];
  189.     CString String;
  190.     POSITION pos;
  191.     int iPos = 0;
  192.     int z;
  193.     
  194.     // Don't flicker like hell!
  195.     ListBox.SetRedraw(FALSE);
  196.     
  197.     // Empty our listbox and start over
  198.     // !!! If we felt like doing more work, we could be smarter than this.
  199.     // This is going to flicker like hell anyway.
  200.     ListBox.ResetContent();
  201.  
  202.     // No Video Options have been set yet
  203.     if ((AVIVideoOptions.dwFlags & AVICOMPRESSF_VALID) == 0) {
  204.         ListBox.AddString(TEXT("Video Compression:  Uninitialized"));
  205.         ListBox.AddString(TEXT(""));
  206.         iPos += 2;
  207.  
  208.     // Johnny, tell us about the Video Options!
  209.     } else {
  210.         HIC hic;                       
  211.         ICINFO icinfo;
  212.         TCHAR szDesc[120] = TEXT("ERROR\0");
  213.         
  214.         // First print "Video Compression:  Compact Video by Cinepak"
  215.         hic = ICOpen(AVIVideoOptions.fccType, 
  216.             AVIVideoOptions.fccHandler, ICMODE_DECOMPRESS);
  217.         if (hic && AVIVideoOptions.fccHandler) {
  218.             ICGetInfo(hic, &icinfo, sizeof(icinfo));
  219.             aviWideToText(szDesc, icinfo.szDescription,
  220.                 sizeof(szDesc)/sizeof(szDesc[0]));
  221.         } else if (AVIVideoOptions.fccHandler == 0)
  222.             lstrcpy(szDesc, TEXT("No Recompression"));
  223.         else if    (AVIVideoOptions.fccHandler == comptypeDIB)
  224.             lstrcpy(szDesc, TEXT("Full Frames"));
  225.         wsprintf(szText, TEXT("Video Compression:  %s"), szDesc);
  226.         ListBox.AddString(szText);
  227.         iPos++;
  228.  
  229.         // Now print "Data Rate: 300 K/Sec    Quality:  7500"
  230.         if (hic && AVIVideoOptions.fccHandler) {
  231.             if (AVIVideoOptions.dwFlags & AVICOMPRESSF_DATARATE)
  232.                 wsprintf(szDesc, TEXT("     Data Rate:  %d K/Sec    Quality:  %d"),
  233.                     (INT)(AVIVideoOptions.dwBytesPerSecond / 1024),
  234.                     (INT)(AVIVideoOptions.dwQuality));
  235.             else
  236.                 wsprintf(szDesc, TEXT("     No Data Rate   Quality:  %d"),
  237.                     (INT)(AVIVideoOptions.dwQuality));
  238.             ListBox.AddString(szDesc);
  239.             iPos++;
  240.         }
  241.  
  242.         // Now print "Key frames every 5 frames" or "No Key frames"
  243.         if (hic && AVIVideoOptions.fccHandler) {
  244.             if (AVIVideoOptions.dwFlags & AVICOMPRESSF_KEYFRAMES)
  245.                 wsprintf(szDesc, TEXT("     Key frames every %d frames"),
  246.                     AVIVideoOptions.dwKeyFrameEvery);
  247.             else
  248.                 lstrcpy(szDesc, TEXT("     No Key frames"));
  249.             ListBox.AddString(szDesc);
  250.             iPos++;
  251.         }
  252.         ListBox.AddString(TEXT(""));
  253.         iPos++;
  254.     }
  255.     
  256.     // There are no Audio Compression options set 
  257.     if ((AVIAudioOptions.dwFlags & AVICOMPRESSF_VALID) == 0) {
  258.         ListBox.AddString(TEXT("Audio Compression:  Uninitialized"));
  259.         ListBox.AddString(TEXT(""));
  260.         iPos += 2;
  261.  
  262.     // Johnny, tell us what they've won!
  263.     } else {
  264.         ACMFORMATDETAILS acmfmt;
  265.         ACMFORMATTAGDETAILS aftd;
  266.         TCHAR szDesc[120] = TEXT("ERROR\0");
  267.     
  268.  
  269.         _fmemset(&acmfmt, 0, sizeof(acmfmt));
  270.         acmfmt.cbStruct = sizeof(acmfmt);
  271.         acmfmt.pwfx = (LPWAVEFORMATEX)AVIAudioOptions.lpFormat;
  272.         acmfmt.cbwfx = AVIAudioOptions.cbFormat;
  273.             acmfmt.dwFormatTag = acmfmt.pwfx->wFormatTag;
  274.             aftd.cbStruct = sizeof(aftd);
  275.             aftd.dwFormatTag = acmfmt.pwfx->wFormatTag;
  276.             aftd.fdwSupport = 0;
  277.  
  278.             if ((acmFormatTagDetails(NULL,&aftd, 
  279.                     ACM_FORMATTAGDETAILSF_FORMATTAG) == 0) &&
  280.                         (acmFormatDetails(NULL, &acmfmt, 
  281.                         ACM_FORMATDETAILSF_FORMAT) == 0)) {
  282.                 wsprintf(szDesc, TEXT("%s %s"),
  283.                 (LPTSTR)acmfmt.szFormat, (LPTSTR)aftd.szFormatTag);
  284.         }
  285.         wsprintf(szText, TEXT("Audio Compression:  %s"), szDesc);
  286.         ListBox.AddString(szText);
  287.         ListBox.AddString(TEXT(""));
  288.         iPos += 2;
  289.     }
  290.     
  291.     // Tell us about the interleaving
  292.     if (AVIAudioOptions.dwFlags & AVICOMPRESSF_INTERLEAVE) {
  293.         wsprintf(szText, TEXT("Interleave every %d frames"),
  294.             (int)AVIAudioOptions.dwInterleaveEvery);
  295.         ListBox.AddString(szText);
  296.         ListBox.AddString(TEXT(""));
  297.         iPos += 2;
  298.     } else {
  299.         ListBox.AddString(TEXT("Not interleaved"));
  300.         ListBox.AddString(TEXT(""));
  301.         iPos += 2;
  302.     }
  303.  
  304.     // Print the Target Directory
  305.     String = TEXT("Target Directory:  ");
  306.     if (TargetDir == "")
  307.         wsprintf(szText, TEXT("Target Directory:  No target directory set"));
  308.     else
  309.         wsprintf(szText, TEXT("Target Directory:  %s"), TargetDir);
  310.     ListBox.AddString(szText);
  311.     ListBox.AddString(TEXT(""));
  312.     iPos += 2;
  313.  
  314.     // List each file.
  315.     pos = FileList.GetHeadPosition();
  316.     if (FileList.IsEmpty()) {
  317.         ListBox.AddString(TEXT("     No Files Added"));
  318.     }
  319.     iFirstFile = iPos;    // Remember where file list starts in list box
  320.     for (z=1; z<=FileList.GetCount(); z++) {
  321.         String = FileList.GetNext(pos);
  322.         wsprintf(szText, TEXT("     %s"), String.GetBuffer(0));
  323.         ListBox.AddString(szText);
  324.     }
  325.          
  326.     ListBox.SetRedraw(TRUE);
  327.     ListBox.Invalidate(FALSE);
  328. }
  329.  
  330. /////////////////////////////////////////////////////////////////////////////
  331. // CBatchDoc diagnostics
  332.  
  333. #ifdef _DEBUG
  334. void CBatchDoc::AssertValid() const
  335. {
  336.     CDocument::AssertValid();
  337. }
  338.  
  339. void CBatchDoc::Dump(CDumpContext& dc) const
  340. {
  341.     CDocument::Dump(dc);
  342. }
  343. #endif //_DEBUG
  344.  
  345. /////////////////////////////////////////////////////////////////////////////
  346. // CBatchDoc commands
  347.  
  348. //
  349. // You can't choose video options while compressing
  350. //
  351. void CBatchDoc::OnUpdateVideo(CCmdUI* pCmdUI) 
  352. {
  353.     pCmdUI->Enable(!fCompressing);
  354.     
  355. }
  356.  
  357. //
  358. // Set the Video Options - all video streams will use these options
  359. //
  360. void CBatchDoc::OnOptionsVideo() 
  361. {
  362.     COMPVARS CompVars;
  363.     BOOL f;
  364.  
  365.     _fmemset(&CompVars, 0, sizeof(CompVars));
  366.     CompVars.cbSize = sizeof(CompVars);
  367.     if (AVIVideoOptions.dwFlags & AVICOMPRESSF_VALID) {
  368.             CompVars.dwFlags = ICMF_COMPVARS_VALID;
  369.             CompVars.fccHandler = AVIVideoOptions.fccHandler;
  370.             CompVars.lQ = AVIVideoOptions.dwQuality;
  371.             CompVars.lpState = AVIVideoOptions.lpParms;
  372.             CompVars.cbState = AVIVideoOptions.cbParms;
  373.             CompVars.lKey =
  374.                 (AVIVideoOptions.dwFlags & AVICOMPRESSF_KEYFRAMES)?
  375.                 (AVIVideoOptions.dwKeyFrameEvery) : 0;
  376.             CompVars.lDataRate =
  377.                 (AVIVideoOptions.dwFlags & AVICOMPRESSF_DATARATE) ?
  378.                 (AVIVideoOptions.dwBytesPerSecond / 1024) : 0;
  379.     }
  380.  
  381.     // !!! It would be nice if we had a parent!
  382.     f = ICCompressorChoose(AfxGetMainWnd()->m_hWnd, 
  383.         ICMF_CHOOSE_KEYFRAME | ICMF_CHOOSE_DATARATE,
  384.         NULL, NULL, &CompVars, NULL);
  385.  
  386.     /* Set the options to our new values */
  387.     if (f) {
  388.             AVIVideoOptions.lpParms = CompVars.lpState;
  389.             AVIVideoOptions.cbParms = CompVars.cbState;
  390.             CompVars.lpState = NULL;       // so it won't be freed
  391.             AVIVideoOptions.fccType = CompVars.fccType;
  392.             AVIVideoOptions.fccHandler = CompVars.fccHandler;
  393.             AVIVideoOptions.dwQuality = CompVars.lQ;
  394.             AVIVideoOptions.dwKeyFrameEvery = CompVars.lKey;
  395.             AVIVideoOptions.dwBytesPerSecond = CompVars.lDataRate * 1024;
  396.             if (CompVars.lKey)
  397.                 AVIVideoOptions.dwFlags |= AVICOMPRESSF_KEYFRAMES;
  398.             else
  399.                 AVIVideoOptions.dwFlags &=~AVICOMPRESSF_KEYFRAMES;
  400.             if (CompVars.lDataRate)
  401.                 AVIVideoOptions.dwFlags |= AVICOMPRESSF_DATARATE;
  402.             else
  403.                 AVIVideoOptions.dwFlags &=~AVICOMPRESSF_DATARATE;
  404.             AVIVideoOptions.dwFlags |= AVICOMPRESSF_VALID;
  405.     }
  406.     ICCompressorFree(&CompVars);
  407.     FixListBox();
  408.     UpdateAllViews(NULL);
  409. }
  410.  
  411. //
  412. // You can't choose audio options while compressing
  413. //
  414. void CBatchDoc::OnUpdateAudio(CCmdUI* pCmdUI) 
  415. {
  416.     pCmdUI->Enable(!fCompressing);
  417. }
  418.  
  419. //
  420. // Set the Audio Options - all audio streams will use these options
  421. //
  422. void CBatchDoc::OnOptionsAudio() 
  423. {
  424.     ACMFORMATCHOOSE acf;
  425.     LONG l;
  426.     MMRESULT f;
  427.  
  428.     AVIAudioOptions.fccType = streamtypeAUDIO;
  429.     _fmemset(&acf, 0, sizeof(acf));
  430.     acf.cbStruct = sizeof(acf);
  431.     // Default to the current settings (if any)
  432.     acf.fdwStyle = (AVIAudioOptions.dwFlags & AVICOMPRESSF_VALID) ?
  433.         ACMFORMATCHOOSE_STYLEF_INITTOWFXSTRUCT : 0;
  434.     acf.hwndOwner = AfxGetMainWnd()->m_hWnd;
  435.     acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, (LPVOID)&l);
  436.     if (AVIAudioOptions.cbFormat == 0) {
  437.         AVIAudioOptions.lpFormat = GlobalAllocPtr(GPTR, l);
  438.         AVIAudioOptions.cbFormat = l;
  439.     }
  440.     acf.pwfx = (LPWAVEFORMATEX)AVIAudioOptions.lpFormat;
  441.     acf.cbwfx = AVIAudioOptions.cbFormat;
  442.     if (acf.pwfx == NULL)    // error: Can't do this
  443.         return;
  444.     f = acmFormatChoose(&acf);
  445.     if (f == MMSYSERR_NOERROR)
  446.         AVIAudioOptions.dwFlags |= AVICOMPRESSF_VALID;
  447.  
  448.     FixListBox();
  449.     UpdateAllViews(NULL);
  450. }
  451.  
  452. //
  453. // Can't choose a target directory while compressing
  454. //
  455. void CBatchDoc::OnUpdateTargetDir(CCmdUI* pCmdUI) 
  456. {
  457.     pCmdUI->Enable(!fCompressing);    
  458. }
  459.  
  460. //
  461. // Choose a target directory for these compressed files
  462. //
  463. void CBatchDoc::OnOptionsTargetDir()
  464. {
  465.     CDestDirDlg DirDlg(AfxGetMainWnd());
  466.     DirDlg.m_DestDir = TargetDir;
  467.     if (DirDlg.DoModal() == IDOK) {
  468.         TargetDir = DirDlg.m_DestDir;
  469.         if (TargetDir.GetAt(TargetDir.GetLength() - 1) != TEXT('\\'))
  470.             TargetDir += TEXT("\\"); 
  471.         FixListBox();     
  472.     }
  473. }
  474.  
  475. //
  476. // Can't add files while compressing
  477. //
  478. void CBatchDoc::OnUpdateAddfile(CCmdUI* pCmdUI) 
  479. {
  480.     pCmdUI->Enable(!fCompressing);    
  481. }
  482.  
  483. //
  484. // Add a file to the list
  485. //
  486. void CBatchDoc::OnOptionsAddfile() 
  487. {
  488.     CFileDialog FileDlg(TRUE, NULL, NULL,
  489.          OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
  490.          TEXT("AVI Files|*.avi|All Files|*.*||"),
  491.          AfxGetMainWnd());
  492.     CString fileName;
  493.  
  494.     if (FileDlg.DoModal() == IDOK) {
  495.         fileName = FileDlg.GetPathName();
  496.         FileList.AddTail(fileName);
  497.         FixListBox();
  498.     }    
  499. }                  
  500.  
  501. //
  502. // Can't change the interleaving while compressing
  503. //
  504. void CBatchDoc::OnUpdateInterleave(CCmdUI* pCmdUI) 
  505. {
  506.     pCmdUI->Enable (!fCompressing);    
  507. }
  508.  
  509. //
  510. // Change the interleaving
  511. //
  512. void CBatchDoc::OnOptionsInterleave() 
  513. {
  514.     CInterleaveDlg InterleaveDlg(AfxGetMainWnd());
  515.     InterleaveDlg.m_InterleaveEvery = AVIAudioOptions.dwInterleaveEvery;
  516.     if (InterleaveDlg.DoModal() == IDOK) {
  517.         AVIAudioOptions.dwFlags |= AVICOMPRESSF_INTERLEAVE;
  518.         AVIAudioOptions.dwInterleaveEvery = InterleaveDlg.m_InterleaveEvery;
  519.         FixListBox();
  520.     }
  521. }
  522.  
  523. #define SLASH(c)     ((c) == '/' || (c) == '\\')
  524.  
  525. /**************************************************************************
  526.  FileName  - return a pointer to the filename part of szPath
  527.              with no preceding path.
  528. ***************************************************************************/
  529. LPTSTR FileName(LPCTSTR lszPath)
  530. {
  531.     LPCTSTR   lszCur;
  532.  
  533.     for (lszCur = lszPath + lstrlen(lszPath); lszCur > lszPath && !SLASH(*lszCur
  534. ) && *lszCur != ':';)
  535.         lszCur = AnsiPrev(lszPath, lszCur);
  536.     if (lszCur == lszPath)
  537.         return (LPTSTR)lszCur;
  538.     else
  539.         return (LPTSTR)(lszCur + 1);
  540. }
  541.  
  542. /****************************************************************************
  543.  CreateDestFile - Take the path part of szPath, append the
  544.              filename part of szName, and return it as szResult.
  545. ****************************************************************************/
  546. static void CreateDestFile(LPTSTR szResult, LPCTSTR szPath, LPCTSTR szName)
  547. {
  548. #if 0
  549.     lstrcpy(szResult, szPath);
  550.     lstrcpy(FileName(szResult), FileName(szName));
  551. #else
  552.     lstrcpy(szResult, szPath);
  553.     lstrcpy(FileName(szResult), FileName(szName));
  554. #endif
  555. }                                  
  556.  
  557. /**************************************************************************
  558.  FixName  -  Given a filespec followed by a space and other text,
  559.              copy just the filespec over to the new string.
  560. ***************************************************************************/
  561. static void FixName(LPTSTR lszFixed, LPCTSTR lszName)
  562. {
  563.     while (*lszName    != ' ' && *lszName != '\0')
  564.         *lszFixed++ = *lszName++;
  565.     *lszFixed = '\0';
  566. }
  567.  
  568. //
  569. // AVISaveV callback where we print our progress as a percentage after the
  570. // filename.
  571. //
  572. HRESULT SaveCallback(int iProgress)
  573. {
  574.     CBatchDoc *lpDoc;
  575.     CString File;
  576.     TCHAR szFile[MAX_PATH + 20];
  577.     TCHAR szText[20];
  578.     int iPos;
  579.     POSITION pos;
  580.     
  581.     // Use ThreadLocalStorage to get the pDoc of this thread so we know
  582.     // which window we are currently in.
  583.     lpDoc = (CBatchDoc *)TlsGetValue(gdwTlsCookie);
  584.     iPos = lpDoc->iCurFile;
  585.     pos = lpDoc->FileList.FindIndex(iPos);
  586.     
  587.     // We've been asked to stop compressing
  588.     if (lpDoc->fStopPlease) {
  589.         lpDoc->fStopPlease = FALSE;
  590.         return AVIERR_USERABORT;    // tells AVISaveV to fail    
  591.     }
  592.  
  593.     // We're further along than last time.  Show our progress by 
  594.     // changing "ski.avi" to "ski.avi <15%>"
  595.     if (iProgress > lpDoc->iPercent) {
  596.         File = lpDoc->FileList.GetAt(pos);
  597.         FixName(szFile, File.GetBuffer(0));
  598.         wsprintf(szText, TEXT("  <%d%%>"), iProgress);
  599.         lstrcat(szFile, szText);
  600.         File = szFile;
  601.         lpDoc->FileList.SetAt(pos, File);
  602.         // Add indent
  603.         lstrcpy(szFile, TEXT("     "));
  604.         lstrcat(szFile, File.GetBuffer(0));
  605.         // Try to be clever... don't update the whole list box.
  606.         // !!! Nice try but no cigar
  607.         lpDoc->ListBox.SetRedraw(FALSE);
  608.         lpDoc->ListBox.DeleteString(lpDoc->iFirstFile + iPos);
  609.         lpDoc->ListBox.InsertString(lpDoc->iFirstFile + iPos, szFile);
  610.         lpDoc->ListBox.SetRedraw(TRUE);
  611.         lpDoc->ListBox.Invalidate(FALSE);
  612.     }
  613.     lpDoc->iPercent = iProgress;
  614.  
  615.     return NOERROR;
  616. }
  617.  
  618. #define MAXSTREAMS 25
  619.     
  620. //
  621. // Compress the file at a given position in this window's list.
  622. //
  623. HRESULT CBatchDoc::CompressFile(int iPos)
  624. {
  625.     POSITION pos = FileList.FindIndex(iPos);
  626.     PAVIFILE pfile;
  627.     PAVISTREAM pavi[MAXSTREAMS];
  628.     LPAVICOMPRESSOPTIONS pOpt[MAXSTREAMS];
  629.     int y;
  630.     AVISTREAMINFOW avis;
  631.     HRESULT hr;
  632.     TCHAR szDest[MAX_PATH];
  633.     TCHAR szFile[MAX_PATH];
  634.     CString File = FileList.GetAt(pos);
  635.     
  636.     FixName(szFile, File.GetBuffer(0));
  637.     hr =AVIFileOpen(&pfile, szFile, 0, 0);
  638.     if (hr == AVIERR_OK && pfile != NULL) {
  639.         
  640.         // Get all the streams in this file and a compression options
  641.         // for each
  642.         for (y = 0; y < MAXSTREAMS; y++) {
  643.             hr = pfile->GetStream(&pavi[y], 0, y);
  644.             if (hr != AVIERR_OK)
  645.                 break;
  646.             pavi[y]->Info(&avis, sizeof(avis));
  647.             if (avis.fccType == streamtypeVIDEO)
  648.                 pOpt[y] = &AVIVideoOptions;
  649.             else if (avis.fccType == streamtypeAUDIO)
  650.                 pOpt[y] = &AVIAudioOptions;
  651.             else
  652.                 ; // ???
  653.         }        
  654.         
  655.         // Create the new filename, and save it
  656.         CreateDestFile(szDest, TargetDir, szFile);
  657.         iPercent = -1;
  658.         iCurFile = iPos; // So Callback knows which file is compressing
  659.         TlsSetValue(gdwTlsCookie, (LPVOID)this);
  660.         hr = AVISaveV(szDest, NULL, (AVISAVECALLBACK)&SaveCallback,
  661.             y, pavi, pOpt);
  662.         
  663.         // Release the streams and file
  664.         for (--y; y>=0; y--) {
  665.             pavi[y]->Release();
  666.         }
  667.         pfile->Release();
  668.     }
  669.     return hr;
  670. }        
  671.  
  672. // A thread is created for each document window.  This function compresses all
  673. // files in the window in series.  Different windows will compress in parallel.
  674. UINT CompressThread(void *pParams)
  675. {
  676.      CBatchDoc *pDoc = (CBatchDoc *) pParams;
  677.  
  678.     HRESULT hr;
  679.     int z, iPos;
  680.     POSITION pos, posT;
  681.     CString String;
  682.     TCHAR szFixed[MAX_PATH];
  683.  
  684.     pDoc->fStopPlease = FALSE;    // just in case it's stuck
  685.     pDoc->fCompressing = TRUE;
  686.  
  687.     AVIFileInit();
  688.  
  689.     // Walk through all the filenames we have to compress
  690.     pos = pDoc->FileList.GetHeadPosition();
  691.     iPos = 0;    // index of pos
  692.     for (z=1; z<=pDoc->FileList.GetCount(); z++) {
  693.         posT = pos;
  694.         String = pDoc->FileList.GetNext(pos);
  695.         iPos++;
  696.         FixName(szFixed, String.GetBuffer(0));
  697.         
  698.         // Do the dirty work
  699.         hr = pDoc->CompressFile(iPos - 1);
  700.  
  701.         // Mark this entry as either <COMPRESSED> or <ERROR> or <ABORTED>
  702.         String = szFixed;
  703.         if (hr == AVIERR_OK)
  704.             String += TEXT("  <COMPRESSED>");
  705.         else if (hr == AVIERR_USERABORT)
  706.             String += TEXT("  <ABORTED>");    
  707.         else 
  708.             String += TEXT("  <ERROR!>");    
  709.         pDoc->FileList.SetAt(posT, String);
  710.         pDoc->FixListBox();
  711.     }
  712.  
  713.     AVIFileExit();
  714.  
  715.     pDoc->fCompressing = FALSE;
  716.  
  717.     return 0;
  718. }
  719.  
  720. #define THREADED    // Use threads.  Otherwise, it will compress everything
  721.             // in series.
  722.  
  723. //
  724. // Can't compress if we're already compressing
  725. //
  726. void CBatchDoc::OnUpdateCompress(CCmdUI* pCmdUI) 
  727. {
  728.     pCmdUI->Enable(!fCompressing);
  729. }
  730.  
  731. //
  732. // Compress every file in this document
  733. //
  734. void CBatchDoc::CompressList() 
  735. {
  736.     if (FileList.IsEmpty() || fCompressing)
  737.         return;
  738.     
  739. #ifdef THREADED
  740.     AfxBeginThread(CompressThread, (void *) this);
  741. #else
  742.     CompressThread(this);
  743. #endif
  744. }                   
  745.  
  746. //
  747. // Compress every file in this document
  748. //
  749. void CBatchDoc::OnOptionsCompress() 
  750. {
  751.     CompressList();
  752. }                   
  753.  
  754. //
  755. // Have we selected something we could delete?
  756. //
  757. void CBatchDoc::OnUpdateDeleteSel(CCmdUI* pCmdUI) 
  758. {
  759.     BOOL f;
  760.     int aSel[1];
  761.  
  762.     // A file is selected if there is a selection and it's in the area of
  763.     // file names, and it's a non-empty list.
  764.     f = (ListBox.GetSelCount() && ListBox.GetSelItems(1, aSel)
  765.         && aSel[0] >= iFirstFile && !FileList.IsEmpty());
  766.     pCmdUI->Enable(f);    
  767. }
  768.  
  769. #define MAXSEL 256    // largest selection we can handle
  770.  
  771. //
  772. // Delete all of the selected filenames from the list box
  773. //
  774. void CBatchDoc::DeleteSelection() 
  775. {
  776.     int cSel, i, j, k = -1;
  777.     int aSel[MAXSEL];
  778.     POSITION pos;
  779.         
  780.     cSel = min(ListBox.GetSelCount(), MAXSEL);
  781.     if (cSel && !FileList.IsEmpty()) {
  782.         ListBox.GetSelItems(cSel, aSel);
  783.         for (i = 0; i < cSel; i++) {
  784.             // The first bunch of items in the list box aren't files 
  785.             j = aSel[i] - iFirstFile;
  786.             if (j >= 0) {
  787.                 if (k == -1)
  788.                     k = i;
  789.                 pos = FileList.FindIndex(j - i + k);
  790.                 FileList.RemoveAt(pos);
  791.             }
  792.         }
  793.     }
  794.     if (k >= 0)
  795.         FixListBox();
  796. }
  797.  
  798. //
  799. // Delete all of the selected filenames from the list box
  800. //
  801. void CBatchDoc::OnOptionsDeleteSel() 
  802. {
  803.     DeleteSelection();
  804. }
  805.  
  806. void CBatchDoc::OnUpdateFileClose(CCmdUI* pCmdUI) 
  807. {
  808.     pCmdUI->Enable(!fCompressing);
  809. }
  810.  
  811. void CBatchDoc::OnUpdateFileSave(CCmdUI* pCmdUI) 
  812. {
  813.     pCmdUI->Enable(!fCompressing);
  814. }
  815.  
  816. void CBatchDoc::OnUpdateFileSaveAs(CCmdUI* pCmdUI) 
  817. {
  818.     pCmdUI->Enable(!fCompressing);
  819. }
  820.